﻿using AleaBelli.Core.Data;
using AleaBelli.Core.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AleaBelli.Core.AI
{
    /// <summary>
    /// Base helper class for all combat algoritmns
    /// </summary>
    public abstract class AbstractCombatAlgorithmn
    {
        private static Logger log = Util.Logger.Instance;

        /// <summary>
        /// Initiate the battle
        /// </summary>
        /// <param name="b"></param>
        public virtual void InitBattle(Battle b)
        {
            // allocate the defenders and attackers to each sub battle 
            SubBattle mainSubBattle = new SubBattle()
            {
                AttackingHex = b.AttackerHex,
                DefendingHex = b.DefendingHex,
                IsMainAttacker = true,
                ActualWidth = GetWidth(b.DefendingHex.TerrainType)
            };
            b.SubBattles.Add(mainSubBattle);

            foreach (Hex h in b.Supporters)
            {
                SubBattle subBattle = new SubBattle()
                {
                    AttackingHex = h,
                    DefendingHex = b.DefendingHex,
                    IsMainAttacker = true,
                    ActualWidth = GetWidth(b.DefendingHex.TerrainType)
                };
                b.SubBattles.Add(subBattle);
            }

            // for each sub battle allocate the attacking forces
            foreach (SubBattle sb in b.SubBattles)
            {
                AllocateAttackers(b, sb);
            }

            // allocate the defenders to each sub battle
            AllocateDefenders(b);
        }

        /// <summary>
        /// Get the number of battalions that can fight in this terrain
        /// </summary>
        /// <param name="terrainType"></param>
        /// <returns></returns>
        public int GetWidth(TerrainType terrainType)
        {
            switch (terrainType)
            {
                case TerrainType.Plain: return 16;
            }

            return 0;
        }

        /// <summary>
        /// Allocate the attackers
        /// </summary>
        /// <param name="b"></param>
        /// <param name="sb"></param>
        void AllocateAttackers(Battle b, SubBattle sb)
        {
            if (log.isDebugEnabled)
            {
                log.Debug(string.Format("AllocateAttackers {0} {1} - {2}", b.Id, b.Name, sb.AttackingHex.Unit.Name));
            }

            // get the battalions
            List<Battalion> battalions = new List<Battalion>();
            sb.AttackingHex.Unit.GetLineBattalions(battalions);

            // sort by effectiveness
            List<Battalion> sortedByEffectivesness = battalions.OrderBy(o => o.ActualEffectiveness(b.DefendingHex.TerrainType)).ToList();


        }

        /// <summary>
        /// Allocate the defendeing forces
        /// 
        ///    1) Determine the strength of each attacking force
        ///    2) Allocate defenders based on perceived strength
        /// </summary>
        /// <param name="b"></param>
        void AllocateDefenders(Battle b)
        {
            if (log.isDebugEnabled)
            {
                log.Debug(string.Format("AllocateDefenders {0} - {1}", b.Id, b.Name));
            }

            // allocate the perceived attacking strength for each sub battle
            foreach (SubBattle sb in b.SubBattles)
            {
                sb.PerceivedAttackingStrength = sb.AttackingHex.Unit.DeterminePerceivedAttackingStrength(sb.DefendingHex.TerrainType);
                if (log.isDebugEnabled)
                {
                    log.Debug(string.Format("Attacking strength {0} = {1}", sb.AttackingHex.Unit.Name, sb.PerceivedAttackingStrength));
                }
            }

            // sort the sub battles by the perceived attacking strength
            List<SubBattle> sortedByStrength = b.SubBattles.OrderBy(o => o.PerceivedAttackingStrength).ToList();

            // allocate defenders to each battle
            List<Battalion> defenders = new List<Battalion>();
            b.DefendingHex.Unit.GetLineBattalions(defenders);

            // boundary case - fewer defenders than attacking directions
            if (defenders.Count < b.SubBattles.Count)
            {


                return;
            }

            // allocate by need


        }
    }
}
